package com.sali.disruptor;

import cn.hutool.core.thread.ThreadFactoryBuilder;
import com.lmax.disruptor.*;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
import com.sali.disruptor.entity.MessageEvent;
import com.sali.disruptor.enums.WaitStrategyEnum;
import lombok.Builder;
import lombok.Data;
import lombok.Singular;

import java.util.List;
import java.util.concurrent.ThreadFactory;

/**
 * @description: disruptor 基础组件
 * @author: sali
 * @date: 2025/2/22 下午2:58.
 * @version: 1.0
 */
@Data
public class DisruptorComponent {

    private final int ringBufferSize;

    private ProducerType producerType;

    private final WaitStrategy waitStrategy;

    private Disruptor<MessageEvent> disruptor;

    @Singular
    private final List<WorkHandler> workHandlers;

    private ExceptionHandler exceptionHandler;

    private ThreadFactory threadFactory;

    /**
     * 线程前缀
     */
    public static final String DISRUPTOR_THREAD_PREFIX = "sali-port-adapter-";

    @Builder(builderMethodName = "createBuilder")
    public DisruptorComponent(int ringBufferSize, ProducerType producerType, WaitStrategyEnum waitStrategyEnum, List<WorkHandler> workHandlers, ExceptionHandler exceptionHandler, ThreadFactory threadFactory) {
        WaitStrategy strategy;
        switch (waitStrategyEnum) {
            case BLOCKING:
                strategy = new BlockingWaitStrategy();
                break;
            case SLEEPING:
                strategy = new SleepingWaitStrategy();
                break;
            case YIELDING:
                strategy = new YieldingWaitStrategy();
                break;
            default:
                strategy = new SleepingWaitStrategy();
                break;
        }
        this.ringBufferSize = ringBufferSize;
        this.producerType = producerType;
        this.waitStrategy = strategy;
        this.workHandlers = workHandlers;
        this.exceptionHandler = exceptionHandler;
        this.threadFactory = threadFactory;
    }

    /**
     * 启动方法
     */
    public void start() {
        if (threadFactory == null) {
            threadFactory = ThreadFactoryBuilder.create().setNamePrefix(DISRUPTOR_THREAD_PREFIX).build();
        }
        disruptor = new Disruptor<>(MessageEvent::new, ringBufferSize, threadFactory, producerType, waitStrategy);
        disruptor.setDefaultExceptionHandler(exceptionHandler);
        disruptor.handleEventsWithWorkerPool(workHandlers.toArray(new WorkHandler[0]));
        disruptor.start();
    }

    /**
     * 销毁方法
     */
    public void distroy() {
        if (disruptor != null) {
            disruptor.shutdown();
        }
    }

}
